home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / pine / help.c < prev    next >
C/C++ Source or Header  |  1996-06-18  |  18KB  |  651 lines

  1. #if !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: help.c,v 4.60 1996/06/18 23:52:50 mikes Exp $";
  3. #endif
  4. /*----------------------------------------------------------------------
  5.  
  6.             T H E    P I N E    M A I L   S Y S T E M
  7.  
  8.    Laurence Lundblade and Mike Seibel
  9.    Networks and Distributed Computing
  10.    Computing and Communications
  11.    University of Washington
  12.    Administration Builiding, AG-44
  13.    Seattle, Washington, 98195, USA
  14.    Internet: lgl@CAC.Washington.EDU
  15.              mikes@CAC.Washington.EDU
  16.  
  17.    Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  18.  
  19.  
  20.    Pine and Pico are registered trademarks of the University of Washington.
  21.    No commercial use of these trademarks may be made without prior written
  22.    permission of the University of Washington.
  23.  
  24.    Pine, Pico, and Pilot software and its included text are Copyright
  25.    1989-1996 by the University of Washington.
  26.  
  27.    The full text of our legal notices is contained in the file called
  28.    CPYRIGHT, included with this distribution.
  29.  
  30.  
  31.    Pine is in part based on The Elm Mail System:
  32.     ***********************************************************************
  33.     *  The Elm Mail System  -  Revision: 2.13                             *
  34.     *                                                                     *
  35.     *             Copyright (c) 1986, 1987 Dave Taylor              *
  36.     *             Copyright (c) 1988, 1989 USENET Community Trust   *
  37.     ***********************************************************************
  38.  
  39.  
  40.   ----------------------------------------------------------------------*/
  41.  
  42. /*======================================================================
  43.      help.c
  44.      Functions to support the pine help screens
  45.  ====*/
  46.  
  47.  
  48. #include "headers.h"
  49.  
  50. /*
  51.  * Internal prototypes
  52.  */
  53. void free_help_text PROTO((char **));
  54.  
  55.  
  56. #ifdef HELPFILE
  57. /*
  58.  * get_help_text - return the help text associated with index
  59.  *                 in an array of pointers to each line of text.
  60.  */
  61. char **
  62. get_help_text(index, pages)
  63. short index;
  64. int   *pages;
  65. {
  66.     int  i, current_page, len;
  67.     char buf[256], **htext, *tmp;
  68.     void copy_fix_keys();
  69.     struct hindx hindex_record;
  70.     FILE *helpfile;
  71. #if !defined(WIN32) && !defined(OS2)
  72.     extern long coreleft();
  73. #endif
  74.  
  75.     if(index < 0 || index >= LASTHELP)
  76.     return(NULL);
  77.  
  78.     /* make sure index file is available, and read appropriate record */
  79.     build_path(buf, ps_global->pine_dir, HELPINDEX);
  80.     if(!(helpfile = fopen(buf, "rb"))){
  81.     q_status_message1(SM_ORDER,3,5,
  82.         "No Help!  Index \"%s\" not found.", buf);
  83.     return(NULL);
  84.     }
  85.  
  86.     i = fseek(helpfile, index * sizeof(struct hindx), SEEK_SET) == 0
  87.      && fread((void *)&hindex_record,sizeof(struct hindx),1,helpfile) == 1;
  88.  
  89.     fclose(helpfile);
  90.     if(!i){    /* problem in fseek or read */
  91.         q_status_message(SM_ORDER, 3, 5,
  92.           "No Help!  Can't locate proper offset for help text file.");
  93.     return(NULL);
  94.     }
  95.  
  96. #if !defined(WIN32) && !defined(OS2)
  97.     if(coreleft() < (long)(80 * hindex_record.lines)){
  98.         q_status_message(SM_ORDER,3,5,
  99.         "No Help!  Not enough memory to display help.");
  100.     return(NULL);
  101.     }
  102. #endif
  103.  
  104.     /* make sure help file is open */
  105.     build_path(buf, ps_global->pine_dir, HELPFILE);
  106.     if((helpfile = fopen(buf, "rb")) == NULL){
  107.     q_status_message2(SM_ORDER,3,5,"No Help!  \"%s\" : %s", buf,
  108.               error_description(errno));
  109.     return(NULL);
  110.     }
  111.  
  112.     if(fseek(helpfile, hindex_record.offset, SEEK_SET) != 0
  113.        || fgets(buf, 255, helpfile) == NULL
  114.        || strncmp(hindex_record.key, buf, strlen(hindex_record.key))){
  115.     /* problem in fseek, or don't see key */
  116.         q_status_message(SM_ORDER, 3, 5,
  117.              "No Help!  Can't locate proper entry in help text file.");
  118.     fclose(helpfile);
  119.     return(NULL);
  120.     }
  121.  
  122.     htext = (char **)fs_get(sizeof(char *) * (hindex_record.lines + 1));
  123.     current_page = 0;
  124.     for(i=0; i < hindex_record.lines; i++){
  125.     if(fgets(buf, 255, helpfile) == NULL){
  126.         htext[i] = NULL;
  127.         free_help_text(htext);
  128.         fclose(helpfile);
  129.             q_status_message(SM_ORDER,3,5,"No Help!  Entry not in help text.");
  130.         return(NULL);
  131.     }
  132.  
  133.     if(*buf){
  134.         if((len = strlen(buf)) > 1
  135.            && (buf[len-2] == '\n' || buf[len-2] == '\r'))
  136.           buf[len-2] = '\0';
  137.         else if(buf[len-1] == '\n' || buf[len-1] == '\r')
  138.           buf[len-1] = '\0';
  139.     }
  140.     else
  141.       len = 0;
  142.  
  143.     htext[i] = NULL;
  144.     if(tmp = srchstr(buf, "___")){
  145.         if(!strcmp(tmp+3, "----")){
  146.         if(pages)
  147.           pages[current_page++] = i;
  148.         }
  149.         else {
  150.         extern char datestamp[];
  151.  
  152.         /* allocate the line (allow for BIG date)... */
  153.         htext[i] = (char *) fs_get(strlen(buf) + 128
  154.                        + strlen(datestamp)
  155.                        + strlen(pine_version));
  156.         /* and copy the new text */
  157.         strcpy(htext[i], buf);
  158.  
  159.         /* loop thru copy replacing strings */
  160.         for(tmp = htext[i]; tmp = srchstr(tmp, "___"); tmp++)
  161.           if(!struncmp(tmp+3, "tdate", 5)){
  162.               char datebuf[128];
  163.               rfc822_date(datebuf);     /* let c-client do the work */
  164.               rplstr(tmp, 8, datebuf);
  165.           }
  166.           else if(!struncmp(tmp+3, "cdate", 5))
  167.             rplstr(tmp, 8, datestamp);
  168.           else if(!struncmp(tmp+3, "version", 7))
  169.             rplstr(tmp, 10, pine_version);
  170.         }
  171.     }
  172.  
  173.     if(!htext[i]){
  174.         htext[i] = (char *)fs_get(len + 1);
  175.         copy_fix_keys(htext[i], buf);
  176.     }
  177.     }
  178.  
  179.     htext[i] = NULL;
  180.     if(pages != NULL)
  181.       pages[current_page] = -1;
  182.  
  183.     fclose(helpfile);
  184.     return(htext);
  185. }
  186. #endif    /* HELPFILE */
  187.  
  188.  
  189. /*
  190.  * free_help_text - free the strings and array of pointers pointed to 
  191.  *                  by text
  192.  */
  193. void
  194. free_help_text(text)
  195.     char **text;
  196. {
  197.     int i = 0;
  198.  
  199.     while(text[i])
  200.       fs_give((void **)&text[i++]);
  201.  
  202.     fs_give((void **)&text);
  203. }
  204.  
  205.  
  206.  
  207. /*----------------------------------------------------------------------
  208.      Make a copy of the help text for display, doing various substutions
  209.  
  210.   Args: a -- output string
  211.         b -- input string
  212.  
  213.  Result: string copied into buffer, and any expressions of the form
  214.  {xxx:yyy} are replaced by either xxx or yyy depending on whether
  215.  we are using function keys or not.  _'s are removed except for the
  216.  special case ^_, which is left as is.
  217.   ----*/
  218.  
  219. void 
  220. copy_fix_keys(a, b)
  221.   register char *a, *b;
  222. {
  223. #if defined(DOS) || defined(OS2)
  224.     register char *s = a;
  225. #endif
  226.     while(*b) {
  227.     while(*b && *b != '{')
  228.           if(*b == '^' && *(b+1) == '_') {
  229.               *a++ = *b++;
  230.               *a++ = *b++;
  231.       } else if(*b == '_' && *(b+1) == '_') {
  232.           while(*b == '_')
  233.         b++;
  234.       }
  235.       else
  236.         *a++ = *b++;
  237.  
  238.     if(*b == '\0') {
  239.         break;
  240.     }
  241.  
  242.     if(F_ON(F_USE_FK,ps_global)) {
  243.         if(*b)
  244.           b++;
  245.         while(*b && *b != ':')
  246.           *a++ = *b++;
  247.         while(*b && *b != '}')
  248.           b++;
  249.         if(*b)
  250.           b++;
  251.     } else {
  252.         while(*b && *b != ':')
  253.           b++;
  254.         if(*b)
  255.           b++;
  256.         while(*b && *b != '}')
  257.           *a++ = *b++;
  258.         if(*b)
  259.           b++;
  260.     }
  261.     }
  262.     *a = '\0';
  263. #if defined(DOS) || defined(OS2)
  264.     b = s;            /* eliminate back-slashes from "a" */
  265.     while(*s){
  266.     if(*s == '\\')
  267.       s++;
  268.  
  269.         *b++ = *s++;
  270.     }
  271.  
  272.     *b = '\0';            /* tie off back-slashed-string */
  273. #endif
  274. }
  275.  
  276.  
  277.  
  278. /*----------------------------------------------------------------------
  279.      Get the help text in the proper format and call scroller
  280.  
  281.     Args: text   -- The help text to display (from pine.help --> helptext.c)
  282.           title  -- The title of the help text 
  283.   
  284.   Result: format text and call scroller
  285.  
  286.   The pages array contains the line number of the start of the pages in
  287. the text. Page 1 is in the 0th element of the array.
  288. The list is ended with a page line number of -1. Line number 0 is also
  289. the first line in the text.
  290.   -----*/
  291. void
  292. #ifdef    HELPFILE
  293.  
  294. helper(text, title, from_composer)
  295.      short  text;
  296.      char   *title;
  297.      int    from_composer;
  298. {
  299.     char **new_text;
  300.  
  301.     if((new_text = get_help_text(text, NULL)) == NULL)
  302.       return;
  303.  
  304.     if(F_ON(F_BLANK_KEYMENU,ps_global)){
  305.     FOOTER_ROWS(ps_global) = 3;
  306.     clearfooter(ps_global);
  307.     ps_global->mangled_screen = 1;
  308.     }
  309.  
  310. #else
  311.  
  312. helper(text, title, from_composer)
  313.      char  *text[], *title;
  314.      int    from_composer;
  315. {
  316.     register char **t, **t2;
  317.     char          **new_text, *tmp;
  318.     int             pages[100], current_page, in_include;
  319.     char            *line, line_buf[256];
  320.     FILE           *file;
  321.     int            alloced_lines = 0;
  322.     int            need_more_lines = 0;
  323.  
  324.  
  325.     dprint(1, (debugfile, "\n\n    ---- HELPER ----\n"));
  326.  
  327.     if(F_ON(F_BLANK_KEYMENU,ps_global)){
  328.     FOOTER_ROWS(ps_global) = 3;
  329.     clearfooter(ps_global);
  330.     ps_global->mangled_screen = 1;
  331.     }
  332.  
  333.     if(from_composer){
  334.      fix_windsize(ps_global);
  335.     init_sigwinch();
  336.     }
  337.  
  338.     /*----------------------------------------------------------------------
  339.             First copy the help text and do substitutions
  340.       ----------------------------------------------------------------------*/
  341.  
  342.     for(t = text ; *t != NULL; t++);
  343.     alloced_lines = t - text;
  344.     new_text = (char **)fs_get((alloced_lines + 1) * sizeof(char *));
  345.  
  346.  
  347.     current_page = 0;
  348.     in_include   = 0;
  349.     file         = NULL;
  350.     for(t = text, t2 = new_text; *t != NULL;) {
  351.         int inc_line_cnt;
  352.         int lines_to_use = ps_global->ttyo->screen_rows
  353.                - HEADER_ROWS(ps_global) - FOOTER_ROWS(ps_global);
  354.         if(in_include) {
  355.             /*--- Inside an ___include ... ___end_include section ---*/
  356.             if(file != NULL) {
  357.  
  358.                 /*--- Read next line out of include file ---*/
  359.  
  360.         /* Add a page break every so often.  This is stupid in that
  361.          * it adds a page break even if there are no more lines.
  362.          */
  363.                 if(inc_line_cnt++ % lines_to_use == 0) {
  364.             /* this is a big long string, don't delete part of it */
  365.                     line = "                                                                         ___----";
  366.                 }else {
  367.                     line = fgets(line_buf, sizeof(line_buf), file);
  368.         }
  369.                 if(line == NULL) {
  370.                     fclose(file);
  371.                     in_include = 0;
  372.                     continue;
  373.                 }
  374.                 if(line[strlen(line)-1] == '\n')
  375.                     line[strlen(line)-1] = '\0';
  376.             } else {
  377.                 /*--- File wasn't there, copy the default text ---*/
  378.                 if(struncmp(*t, "___end_include", 14) == 0){
  379.                     in_include = 0;
  380.                     t++;
  381.                     continue;
  382.                 } else {
  383.                     line = *t;
  384.                 }
  385.             }
  386.         } else {
  387.             if(struncmp(*t, "___include", 10) == 0) {
  388.                 /*-- Found start of an ___include ... ___end_include block --*/
  389.                 char *p, *q, **pp;
  390.         int cnt;
  391.                 in_include = 1;
  392.                 inc_line_cnt = (current_page > 0)
  393.                           ? t2 - new_text - pages[current_page-1]
  394.                   : t2 - new_text;
  395.                 for(p = (*t)+10; *p && isspace((unsigned char)*p); p++);
  396.                 strcpy(line_buf, p);
  397.                 for(q = line_buf; *q && !isspace((unsigned char)*q); q++);
  398.                 *q = '\0';
  399.                 dprint(9, (debugfile, "About to open \"%s\"\n", line_buf));
  400.                 file = fopen(line_buf, "r");
  401.                 if(file != NULL) {
  402.           /*
  403.            * Calculate the size of the included file,
  404.            * might have to resize new_text.
  405.            */
  406.            for(cnt=0; fgets(line_buf, sizeof(line_buf), file) != NULL;
  407.                                    cnt++);
  408.                    /* add lines so we can insert page breaks if necessary */
  409.                    cnt = cnt + (inc_line_cnt-1+cnt)/(lines_to_use - 1);
  410.            /* rewind */
  411.            (void)fseek(file, 0L, 0);
  412.             /*
  413.              * Skip t forward to the end_include so that we know
  414.              * how many lines we're skipping.
  415.              */
  416.            pp = t;
  417.                    while(*t && struncmp(*t, "___end_include", 14) != 0)
  418.                      t++;
  419.            /* we need cnt more lines but freed up t-pp+1 lines */
  420.            need_more_lines += cnt - (t - pp + 1);
  421.            if(need_more_lines > 0) {
  422.              int offset = t2 - new_text;
  423.              alloced_lines += need_more_lines;
  424.              need_more_lines = 0;
  425.              fs_resize((void **)&new_text,
  426.                    (alloced_lines + 1) * sizeof(char *));
  427.              t2 = &new_text[offset];
  428.            }
  429.         }else {
  430.                   dprint(1, (debugfile,"Helptext Failed open \"%s\": \"%s\"\n",
  431.                              line_buf, error_description(errno)));
  432.         }
  433.                 t++;
  434.                 continue;
  435.             }  else {
  436.                 /*-- The normal case, just another line of help text ---*/
  437.                 line = *t;
  438.             }
  439.         }
  440.  
  441.         /*-- line now contains the text to use, where ever it came from --*/
  442.         dprint(9, (debugfile, "line-->%s<-\n", line));
  443.  
  444.     *t2 = NULL;
  445.     if(tmp = srchstr(line, "___")){
  446.         if(!strcmp(tmp+3, "----")){
  447.         pages[current_page++] = t2 - new_text;
  448.         }
  449.         else{
  450.         extern char datestamp[];
  451.  
  452.         /* allocate the line (allow for BIG date)... */
  453.         *t2 = (char *) fs_get(strlen(line) + 128
  454.                       + strlen(datestamp)
  455.                       + strlen(pine_version));
  456.         /* and copy the new text */
  457.         strcpy(*t2, line);
  458.  
  459.         /* loop thru copy replacing strings */
  460.         for(tmp = *t2; tmp = srchstr(tmp, "___"); tmp++)
  461.           if(!struncmp(tmp+3, "tdate", 5)){
  462.               char datebuf[128];
  463.               rfc822_date(datebuf);     /* let c-client do the work */
  464.               rplstr(tmp, 8, datebuf);
  465.           }
  466.           else if(!struncmp(tmp+3, "cdate", 5))
  467.             rplstr(tmp, 8, datestamp);
  468.           else if(!struncmp(tmp+3, "version", 7))
  469.             rplstr(tmp, 10, pine_version);
  470.         }
  471.     }
  472.  
  473.     if(!*t2){
  474.         *t2 = (char *)fs_get(strlen(line) + 1);
  475.         copy_fix_keys(*t2, line);
  476.     }
  477.  
  478.         t2++;
  479.     if(!in_include || (in_include && file == NULL))
  480.             t++;
  481.     }
  482.     *t2 = *t;
  483.     pages[current_page] = -1;
  484.  
  485.     dprint(7, (debugfile, "helper PAGE COUNT %d\n", current_page));
  486.     { int i;
  487.         for(i = 0 ; pages[i] != -1; i++) 
  488.          dprint(7, (debugfile, "helper PAGE %d line %d [%s]\n",i+1, pages[i],
  489.                     new_text[pages[i]]));
  490.     }
  491. #endif    /* HELPFILE */
  492.  
  493. #ifdef _WINDOWS
  494.     /* Under windows, throw the help text into a window. */
  495.     if (mswin_displaytext (title, NULL, 0, new_text, 0, 0) >= 0) 
  496.       return;
  497.     /* Buf if the window fails, fall through and display in main window. */
  498. #endif
  499.  
  500.     /* This is mostly here to get the curses variables for line and column
  501.         in sync with where the cursor is on the screen. This gets warped
  502.     when the composer is called because it does it's own stuff */
  503.     ClearScreen();
  504.     scrolltool((void *)new_text, title,
  505.                (text == main_menu_tx)
  506.              ? MainHelpText
  507.          : from_composer
  508.            ? ComposerHelpText
  509.            : HelpText,
  510.            CharStarStar, (ATTACH_S *)NULL);
  511.  
  512.     if(F_ON(F_BLANK_KEYMENU,ps_global))
  513.       FOOTER_ROWS(ps_global) = 1;
  514.  
  515.     ClearScreen();
  516.  
  517.     free_help_text(new_text);
  518. }
  519.  
  520.  
  521. void
  522. print_all_help()
  523. {
  524. #ifdef    HELPFILE
  525.     short t;
  526.     char **l, **h, buf[500];
  527. #else
  528.     char ***t, **l, buf[500];
  529. #endif
  530.     int     line_count;
  531.  
  532.     if(open_printer("all 50+ pages of help text ") == 0) {
  533. #ifdef    HELPFILE
  534.         for(t = 0; t < LASTHELP; t++) {
  535.         if((h = get_help_text(t, NULL)) == NULL){
  536.         return;
  537.             }
  538.             for(l = h; *l != NULL; l++) {
  539. #else
  540.         for(t = h_texts; *t != NULL; t++) {
  541.             line_count = 0;
  542.             for(l = *t; *l != NULL; l++) {
  543. #endif
  544.                 copy_fix_keys(buf, *l);
  545.                 print_text(buf);
  546.                 print_char('\n');
  547.                 line_count++;
  548.             }
  549.  
  550.             if(line_count <= 10){
  551.         print_text(NEWLINE);
  552.         print_text(NEWLINE);
  553.         }
  554.         else{
  555.         print_char(ctrl('L'));
  556.         print_text(NEWLINE);
  557.         }
  558.         }
  559.         close_printer();
  560.     }
  561. }
  562.  
  563.  
  564. #if defined(DOS) && !defined(_WINDOWS)
  565. #define NSTATUS 25  /* how many status messages to save for review */
  566. #else
  567. #define NSTATUS 100
  568. #endif
  569.  
  570. static char *stat_msgs[NSTATUS];
  571. static int   latest;
  572.  
  573. /*----------------------------------------------------------------------
  574.      Review last N status messages
  575.  
  576.     Args: title  -- The title of the screen
  577.   -----*/
  578. void
  579. review_messages(title)
  580.     char  *title;
  581. {
  582.     int             how_many = 0;
  583.     char          **tmp_text;
  584.     register char **e;
  585.     register int    i, j;
  586.  
  587.     e = stat_msgs;
  588.     tmp_text = (char **)fs_get((NSTATUS + 1) * sizeof(char *));
  589.  
  590.     /* allocate strings */
  591.     for(j = 0, i = latest+1; i < NSTATUS; i++)
  592.       if(e[i] && *e[i])
  593.     tmp_text[j++] = cpystr(e[i]);
  594.  
  595.     for(i = 0; i <= latest; i++)
  596.       if(e[i] && *e[i])
  597.     tmp_text[j++] = cpystr(e[i]);
  598.     
  599.     /* scrolltool expects NULL at end */
  600.     tmp_text[j] = NULL;
  601.     how_many = j;
  602.  
  603.     scrolltool((void *)tmp_text, title, ReviewMsgsText,
  604.     CharStarStar, (ATTACH_S *)NULL);
  605.  
  606.     /* free everything */
  607.     for(j = 0; j < how_many; j++)
  608.       fs_give((void **)&tmp_text[j]);
  609.  
  610.     fs_give((void **)&tmp_text);
  611. }
  612.  
  613.  
  614. /*----------------------------------------------------------------------
  615.      Add a message to the circular status message review buffer
  616.  
  617.     Args: message  -- The message to add
  618.   -----*/
  619. void
  620. add_review_message(message)
  621.     char *message;
  622. {
  623.     if(!(message && *message))
  624.       return;
  625.  
  626.     latest = (latest + 1) % NSTATUS;
  627.     if(stat_msgs[latest] && strlen(stat_msgs[latest]) >= strlen(message))
  628.       strcpy(stat_msgs[latest], message);  /* already enough space */
  629.     else{
  630.     if(stat_msgs[latest])
  631.       fs_give((void **)&stat_msgs[latest]);
  632.  
  633.     stat_msgs[latest] = cpystr(message);
  634.     }
  635. }
  636.  
  637.  
  638.  
  639. /*----------------------------------------------------------------------
  640.     Free resources associated with the status message review list
  641.  
  642.     Args: 
  643.   -----*/
  644. void
  645. end_status_review()
  646. {
  647.     for(latest = NSTATUS - 1; latest >= 0; latest--)
  648.       if(stat_msgs[latest])
  649.     fs_give((void **)&stat_msgs[latest]);
  650. }
  651.